package Analizador_Lexico;

import java.util.Hashtable;

import exceptions.lexic.*;;


/**
*
* @author Mar & Luis 
*
*/
public class Token {

    private TipoToken tipoToken;
    private String lexema;
    private int linea;
    private int columna;

/********************************************************************************************************/
// Tokens reconocidos por el analizador
/*******************************************************************************************************/    
public enum TipoToken {
    NOT,IF,ELSE, PUNTO, WHILE,RETURN, CLASS,NEW,SUPER,
	IDENTIFICADOR, NUMERO, PRODUCTO,THIS,EXTENDS,BOOLEAN,CHAR,INT,FOR,VOID,STRING,
    COMA, PUNTOYCOMA, ASIG, PARABRE, PARCIERRA, AND,CLASSDEF,
    OR, DIV,IGUAL, EOF, LLAVEABRE, LLAVECIERRA, CORCHETEABRE, CORCHETECIERRA,
    TRUE, NULL, FALSE, PORCENT, MAYORYIGUAL, MENORYIGUAL, MAYOR, MENOR, DISTINTO, 
    COMILLASIMPLE, COMILLADOBLE, MAS, MENOS, CARACTER, CADENA;
}

private static Hashtable<String, TipoToken> tablaTokens;
static{
	    tablaTokens = new Hashtable<String, TipoToken>(45); 
		tablaTokens.put("if",TipoToken.IF);
		tablaTokens.put("return",TipoToken.RETURN);
		tablaTokens.put("else",TipoToken.ELSE);
		tablaTokens.put("while",TipoToken.WHILE);
		tablaTokens.put("classDef",TipoToken.CLASSDEF);
		tablaTokens.put("class",TipoToken.CLASS);
		tablaTokens.put("new",TipoToken.NEW);
		tablaTokens.put("super",TipoToken.SUPER);
		tablaTokens.put("this",TipoToken.THIS);
		tablaTokens.put("extends",TipoToken.EXTENDS);
		tablaTokens.put("boolean",TipoToken.BOOLEAN);
		tablaTokens.put("char",TipoToken.CHAR);
		tablaTokens.put("int",TipoToken.INT);
		tablaTokens.put("for",TipoToken.FOR);
		tablaTokens.put("void",TipoToken.VOID);
		tablaTokens.put("String",TipoToken.STRING);		
        tablaTokens.put("false",TipoToken.FALSE);
        tablaTokens.put("true",TipoToken.TRUE);
        tablaTokens.put("null",TipoToken.NULL);
        tablaTokens.put("(",TipoToken.PARABRE);
        tablaTokens.put(")",TipoToken.PARCIERRA);
        tablaTokens.put("{",TipoToken.LLAVEABRE);
        tablaTokens.put("}",TipoToken.LLAVECIERRA);
        tablaTokens.put("[",TipoToken.CORCHETEABRE);
        tablaTokens.put("]",TipoToken.CORCHETECIERRA);
        tablaTokens.put("=",TipoToken.ASIG);
        tablaTokens.put(".",TipoToken.PUNTO);
        tablaTokens.put(",",TipoToken.COMA);
        tablaTokens.put(";",TipoToken.PUNTOYCOMA);

        tablaTokens.put("+",TipoToken.MAS);
        tablaTokens.put("-",TipoToken.MENOS);
        tablaTokens.put("==",TipoToken.IGUAL);
        tablaTokens.put("*",TipoToken.PRODUCTO);
        tablaTokens.put("/",TipoToken.DIV);
        tablaTokens.put("!",TipoToken.NOT);
        tablaTokens.put("&&",TipoToken.AND);
        tablaTokens.put("||",TipoToken.OR);
        tablaTokens.put("%",TipoToken.PORCENT);
        tablaTokens.put(">=",TipoToken.MAYORYIGUAL);
        tablaTokens.put("<=",TipoToken.MENORYIGUAL);
        tablaTokens.put(">",TipoToken.MAYOR);
        tablaTokens.put("<",TipoToken.MENOR);
        tablaTokens.put("!=",TipoToken.DISTINTO);
        tablaTokens.put("EOF",TipoToken.EOF);

      
    }

/**********************************************************************************************************/
//Palabras prohibidas 
/**********************************************************************************************************/
public enum TipoForbidden {
	ABSTRACT, DEFAULT, LONG, SWITCH, TRY, BYTE, DO, IMPLEMENTS, NATIVE, SYNCHRONIZED, VOLATILE, 
	CASE, DOUBLE, IMPORT, GOTO, THROW, CATCH, FINAL, INSTANCEOF, THROWS, PACKAGE, CONST, FINALLY, INTERFACE, 
	SHORT, TRANSIENT, BREAK, CONTINUE, PRIVATE, PROTECTED, PUBLIC, STATIC, NOSOPORTADO;}

private static Hashtable<String, TipoForbidden> tablaForbidden;
static{
	    tablaForbidden = new Hashtable<String, TipoForbidden>(32);
     
		tablaForbidden.put("abstract",TipoForbidden.ABSTRACT);
		tablaForbidden.put("default",TipoForbidden.DEFAULT);
		tablaForbidden.put("long",TipoForbidden.LONG);
		tablaForbidden.put("switch",TipoForbidden.SWITCH);
		tablaForbidden.put("try",TipoForbidden.TRY);
		tablaForbidden.put("byte",TipoForbidden.BYTE);
		tablaForbidden.put("do",TipoForbidden.DO);
		tablaForbidden.put("implements",TipoForbidden.IMPLEMENTS);
		tablaForbidden.put("native",TipoForbidden.NATIVE);
		tablaForbidden.put("synchronized",TipoForbidden.SYNCHRONIZED);
		tablaForbidden.put("volatile",TipoForbidden.VOLATILE);
		tablaForbidden.put("case",TipoForbidden.CASE);
		tablaForbidden.put("double",TipoForbidden.DOUBLE);
		tablaForbidden.put("import",TipoForbidden.IMPORT);
		tablaForbidden.put("goto",TipoForbidden.GOTO);
		tablaForbidden.put("catch",TipoForbidden.CATCH);
		tablaForbidden.put("final",TipoForbidden.FINAL);
		tablaForbidden.put("instanceof",TipoForbidden.INSTANCEOF);
		tablaForbidden.put("package",TipoForbidden.PACKAGE);
		tablaForbidden.put("throws",TipoForbidden.THROWS);
		tablaForbidden.put("throws",TipoForbidden.THROWS);
		tablaForbidden.put("const",TipoForbidden.CONST);
		tablaForbidden.put("finally",TipoForbidden.FINALLY);
		tablaForbidden.put("interface",TipoForbidden.INTERFACE);
		tablaForbidden.put("short",TipoForbidden.SHORT);
		tablaForbidden.put("transient",TipoForbidden.TRANSIENT);
		tablaForbidden.put("break",TipoForbidden.BREAK);
		tablaForbidden.put("continue",TipoForbidden.CONTINUE);
		tablaForbidden.put("private",TipoForbidden.PRIVATE);
		tablaForbidden.put("protected",TipoForbidden.PROTECTED);
		tablaForbidden.put("public",TipoForbidden.PUBLIC);
		tablaForbidden.put("static",TipoForbidden.STATIC);
}		
		

/**********************************************************************************************************/
//Palabras reservadas para posible extension de Java
/**********************************************************************************************************/
public enum TipoReserved {
	BYVALUE, NONE, CAST, OPERATOR, FUTURE, OUTER, GENERIC, REST, INNER, VAR;
}

private static Hashtable<String, TipoReserved> tablaReserved;
static{
	    tablaReserved = new Hashtable<String, TipoReserved>(10);
     
		tablaReserved.put("byvalue",TipoReserved.BYVALUE);
		tablaReserved.put("none",TipoReserved.NONE);
		tablaReserved.put("cast",TipoReserved.CAST);
		tablaReserved.put("operator",TipoReserved.OPERATOR);
		tablaReserved.put("future",TipoReserved.FUTURE);
		tablaReserved.put("outer",TipoReserved.OUTER);
		tablaReserved.put("generic",TipoReserved.GENERIC);
		tablaReserved.put("rest",TipoReserved.REST);
		tablaReserved.put("inner",TipoReserved.INNER);
		tablaReserved.put("var",TipoReserved.VAR);
    }

/**********************************************************************************************************/
    public Token(TipoToken tipoToken, String lexema, int linea, int columna) {
        this.tipoToken=tipoToken;
        this.lexema=lexema;
        this.linea=linea;
        this.columna=columna;
     
    }

    public String toString(){
    	String token = tipoToken.toString();
        String cadena;
        if(token.length()<=8){
                cadena = "Token: "+token+"\t\t";
        }
        else{
            cadena = "Token: "+token+"\t";
        }
        cadena+=" - Lexema: ";
        String l = lexema.toString();
        if(l.length()<=4){
                cadena = cadena+l+"\t\t";
        }
        else{
            cadena = cadena+l+"\t";
        }
    	return (cadena+"- Linea: "+String.valueOf(linea)+"\n");
	}

    public static TipoToken getTipo(String id, int linea, int columna) throws ForbiddenWordException, ReservedWordException{
    	
    	TipoToken tt = tablaTokens.get(id);	
		if (tt == null){
			TipoForbidden tf = tablaForbidden.get(id);
			if (tf != null){ 
                throw new ForbiddenWordException(id,linea, columna);
			}else{
				TipoReserved tr = tablaReserved.get(id);
				if (tr!=null){
					throw new ReservedWordException(id,linea, columna);
				}else{
					return TipoToken.IDENTIFICADOR;
				}
			}
		}else{
			return tt;
		}  
    }

    public TipoToken getTipo(){
        return tipoToken;
    }

    public String getLexema(){
        return lexema;
    }

    public int getLinea(){
        return linea;
    }
    
    public int getColumna(){
        return columna;
    }


}
